
require 'net/http'

module Oos4ruby
class HTTPInvoker
  
  attr_reader :response, :headers, :entry, :body
  
  def initialize(uri, authent)
    @uri = (uri if uri.kind_of?URI) || URI.parse(uri)
    @authent = authent
    
    @headers = {}
    @entry = nil
  end
  
  def set_header(name, val)
    @headers[name.to_s.gsub(/_/, '-')] = val
  end
  
  def get(depth = 0, req = nil)           
    return false unless is_authenticate?depth, req
    
    http, req = prepare_http req, :get
    
    http.start do |connection|
      @response = connection.request(req)

      return get(depth + 1, req) if need_authentication?(req)

      if @response.kind_of?Net::HTTPSuccess
        @body = @response.body
        return true
      end 

      
      return false
    end      
    
  end
  
  def post(contentType, body, depth = 0, req = nil)    
    return false unless is_authenticate?depth, req
    
    http, req = prepare_http req, :post
    
    req.set_content_type contentType
    @headers.each { |k, v| req[k]= v }

    http.start do |connection|
      if body.instance_of?String
        @response = connection.request(req, body)
      else
        req.body_stream = body
        @response = connection.request(req)
      end

      return post(contentType, body, depth + 1, req) if need_authentication?(req)

      return false if @response.code != '201'

      begin
        @entry = Entry.new @response.body
        return true
      rescue ArgumentError          
        return false
      end
    end
    
  end
  
  def put(contentType, body, depth = 0, req = nil)    
    return false unless is_authenticate?depth, req
    
    http, req = prepare_http req, :put    
    
    req.set_content_type contentType
    @headers.each { |k, v| req[k]= v }

    http.start do |connection|
      @response = connection.request(req, body)

      return put(contentType, body, depth +1, req) if need_authentication?(req)

      return true if @response.kind_of? Net::HTTPSuccess        

      return false
    end
    
  end
  
  def delete( req = nil, depth = 0 )
    return false unless is_authenticate?depth, req

    http, req = prepare_http req, :delete
    
    http.start do |connection|
      @response = connection.request(req)

      return delete(req, depth + 1) if need_authentication?(req)

      return true if @response.kind_of? Net::HTTPSuccess

      return false
    end

  end
  
  private
  def header(which)
    @response[which]
  end
  
  def prepare_http( req, option )
    http = Net::HTTP.new(@uri.host, @uri.port)
    http.use_ssl = true if @uri.scheme == 'https'    
    
    unless req
      url = @uri.path
      url += "?#{@uri.query}" if @uri.query
      req = eval("Net::HTTP::#{option.to_s.capitalize}").new( url )
    end
    
    @authent.add_to req
    return http, req
  end
  
  def need_authentication?(req)    
    if @response.instance_of?(Net::HTTPUnauthorized) && @authent      
      @authent.add_to req      
      req.body = nil unless req.body.nil?
      req.body_stream = nil unless req.body_stream.nil?
      return true
    end
    return false 
  end
  
  def is_authenticate?(depth, req)
    return false if depth > 2 and need_authentication?(req)          
    return true
  end
  
end
end